package com.example.data.network

import android.content.Context
import android.util.Log
import com.example.data.model.DataProductModel
import com.example.domain.model.LoginRes
import com.example.domain.model.Product
import com.example.domain.network.NetworkService
import com.example.domain.network.ResultWrapper
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.plugins.ClientRequestException
import io.ktor.client.plugins.ServerResponseException
import io.ktor.client.request.request
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.http.ContentType
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpMethod
import io.ktor.http.Parameters
import io.ktor.http.contentType
import io.ktor.util.InternalAPI
import io.ktor.utils.io.errors.IOException
import kotlinx.serialization.InternalSerializationApi

class NetworkServiceImpl(
    val client: HttpClient,
    private val context: Context
) : NetworkService {
  private val baseUrl = "https://fakestoreapi.com"
  private val tokenManager by lazy { TokenManager.getInstance(context) }

  @OptIn(InternalSerializationApi::class)
  override suspend fun getProducts(category: String?): ResultWrapper<List<Product>> {
    val url =
      if (category != null) "$baseUrl/products/category/$category" else "$baseUrl/products"

    return makeWebRequest(
      url = url,
      method = HttpMethod.Get,
      mapper = { dataModels: List<DataProductModel> ->
        dataModels.map { it.toProduct() }
      }
    )
  }

  override suspend fun getCategories(): ResultWrapper<List<String>> {
    val url = "$baseUrl/products/categories"
    return makeWebRequest<List<String>, List<String>>(
      url = url,
      method = HttpMethod.Get
    )
  }

  @OptIn(InternalSerializationApi::class)
  override suspend fun login(username: String, password: String): ResultWrapper<LoginRes> {
    val url = "http://47.92.157.229:8888/login"
    return try {
      Log.d("Network", "Login request: username=$username, password=$password")
      val response = client.post(url) {
        contentType(ContentType.Application.Json)
        setBody(mapOf(
          "username" to username,
          "password" to password
        ))
      }.body<LoginRes>()
      Log.d("Network", "Login response: $response")
      
      // 保存token
      response.token?.let { tokenManager.saveToken(it) }
      
      ResultWrapper.Success(response)
    } catch (e: ClientRequestException) {
      Log.d("Network", "ClientRequestException: ${e.message}")
      ResultWrapper.Failure(e)
    } catch (e: ServerResponseException) {
      Log.d("Network", "ServerResponseException: ${e.message}")
      ResultWrapper.Failure(e)
    } catch (e: IOException) {
      Log.d("Network", "IOException: ${e.message}")
      ResultWrapper.Failure(e)
    } catch (e: Exception) {
      Log.d("Network", "Exception: ${e.message}")
      ResultWrapper.Failure(e)
    }
  }

  @OptIn(InternalAPI::class)
  internal suspend inline fun <reified T, R> makeWebRequest(
    url: String,
    method: HttpMethod,
    body: Any? = null,
    headers: Map<String, String> = emptyMap(),
    parameters: Map<String, String> = emptyMap(),
    noinline mapper: ((T) -> R)? = null
  ): ResultWrapper<R> {
    Log.d("Network", "makeWebRequest: $url")
    Log.d("Network", "body: $body")
    return try {
      val response = client.request(url) {
        this.method = method
        url {
          this.parameters.appendAll(Parameters.build {
            parameters.forEach { (key, value) ->
              append(key, value)
            }
          })
        }

        // 添加自定义请求头
        headers.forEach { (key, value) ->
          this.headers.append(key, value)
        }
        
        // 如果有token，添加Authorization头
        tokenManager.getToken()?.let { token ->
          this.headers.append(HttpHeaders.Authorization, "Bearer $token")
          Log.d("Network", "Adding Authorization header: Bearer $token")
        }
        
        if (body != null) {
          contentType(ContentType.Application.Json)
          this.body = body
        }
      }.body<T>()
      Log.d("Network", "response: $response")
      val result: R = mapper?.invoke(response) ?: response as R
      ResultWrapper.Success(result)
    }catch (e: ClientRequestException) {
      Log.d("Network", "ClientRequestException: ${e.message}")
      ResultWrapper.Failure(e)
    }catch (e: ServerResponseException) {
      Log.d("Network", "ServerResponseException: ${e.message}")
      ResultWrapper.Failure(e)
    }catch (e: IOException) {
      Log.d("Network", "IOException: ${e.message}")
      ResultWrapper.Failure(e)
    }catch (e: Exception) {
      Log.d("Network", "Exception: ${e.message}")
      ResultWrapper.Failure(e)
    }
  }
}